home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / hplip / base / status.py < prev    next >
Text File  |  2008-10-13  |  53KB  |  1,389 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. from __future__ import division
  23.  
  24. # Std Lib
  25. import struct
  26. import cStringIO 
  27. import xml.parsers.expat as expat
  28. import re
  29.  
  30. # Local
  31. from g import *
  32. from codes import *
  33. import pml, utils
  34.  
  35.  
  36. """
  37. status dict structure:
  38.     { 'revision' :     STATUS_REV_00 .. STATUS_REV_04,
  39.       'agents' :       [ list of pens/agents/supplies (dicts) ],
  40.       'top-door' :     TOP_DOOR_NOT_PRESENT | TOP_DOOR_CLOSED | TOP_DOOR_OPEN,
  41.       'status-code' :  STATUS_...,
  42.       'supply-door' :  SUPPLY_DOOR_NOT_PRESENT | SUPPLY_DOOR_CLOSED | SUPPLY_DOOR_OPEN.
  43.       'duplexer' :     DUPLEXER_NOT_PRESENT | DUPLEXER_DOOR_CLOSED | DUPLEXER_DOOR_OPEN,
  44.       'photo_tray' :   PHOTO_TRAY_NOT_PRESENT | PHOTO_TRAY_ENGAGED | PHOTO_TRAY_NOT_ENGAGED,
  45.       'in-tray1' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
  46.       'in-tray2' :     IN_TRAY_NOT_PRESENT | IN_TRAY_CLOSED | IN_TRAY_OPEN (| IN_TRAY_DEFAULT | IN_TRAY_LOCKED)*,
  47.       'media-path' :   MEDIA_PATH_NOT_PRESENT | MEDIA_PATH_CUT_SHEET | MEDIA_PATH_BANNER | MEDIA_PATH_PHOTO,
  48.     }
  49.  
  50.     * S:02 only
  51.  
  52. agent dict structure: (pens/supplies/agents/etc)
  53.     { 'kind' :           AGENT_KIND_NONE ... AGENT_KIND_ADF_KIT,
  54.       'type' :           TYPE_BLACK ... AGENT_TYPE_UNSPECIFIED,      # aka color
  55.       'health' :         AGENT_HEALTH_OK ... AGENT_HEALTH_UNKNOWN,
  56.       'level' :          0 ... 100,
  57.       'level-trigger' :  AGENT_LEVEL_TRIGGER_SUFFICIENT_0 ... AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  58.     }
  59. """
  60.  
  61.  
  62.  
  63. # 'revision'
  64. STATUS_REV_00 = 0x00
  65. STATUS_REV_01 = 0x01
  66. STATUS_REV_02 = 0x02
  67. STATUS_REV_03 = 0x03
  68. STATUS_REV_04 = 0x04
  69. STATUS_REV_V  = 0xff
  70. STATUS_REV_UNKNOWN = 0xfe
  71.  
  72. vstatus_xlate  = {'busy' : STATUS_PRINTER_BUSY,
  73.                    'idle' : STATUS_PRINTER_IDLE,
  74.                    'prnt' : STATUS_PRINTER_PRINTING,
  75.                    'offf' : STATUS_PRINTER_TURNING_OFF,
  76.                    'rprt' : STATUS_PRINTER_REPORT_PRINTING,
  77.                    'cncl' : STATUS_PRINTER_CANCELING,
  78.                    'iost' : STATUS_PRINTER_IO_STALL,
  79.                    'dryw' : STATUS_PRINTER_DRY_WAIT_TIME,
  80.                    'penc' : STATUS_PRINTER_PEN_CHANGE,
  81.                    'oopa' : STATUS_PRINTER_OUT_OF_PAPER,
  82.                    'bnej' : STATUS_PRINTER_BANNER_EJECT,
  83.                    'bnmz' : STATUS_PRINTER_BANNER_MISMATCH,
  84.                    'phmz' : STATUS_PRINTER_PHOTO_MISMATCH,
  85.                    'dpmz' : STATUS_PRINTER_DUPLEX_MISMATCH,
  86.                    'pajm' : STATUS_PRINTER_MEDIA_JAM,
  87.                    'cars' : STATUS_PRINTER_CARRIAGE_STALL,
  88.                    'paps' : STATUS_PRINTER_PAPER_STALL,
  89.                    'penf' : STATUS_PRINTER_PEN_FAILURE,
  90.                    'erro' : STATUS_PRINTER_HARD_ERROR,
  91.                    'pwdn' : STATUS_PRINTER_POWER_DOWN,
  92.                    'fpts' : STATUS_PRINTER_FRONT_PANEL_TEST,
  93.                    'clno' : STATUS_PRINTER_CLEAN_OUT_TRAY_MISSING}
  94.  
  95. REVISION_2_TYPE_MAP = {0 : AGENT_TYPE_NONE,
  96.                         1 : AGENT_TYPE_BLACK,
  97.                         2 : AGENT_TYPE_CYAN,
  98.                         3 : AGENT_TYPE_MAGENTA,
  99.                         4 : AGENT_TYPE_YELLOW,
  100.                         5 : AGENT_TYPE_BLACK,
  101.                         6 : AGENT_TYPE_CYAN,
  102.                         7 : AGENT_TYPE_MAGENTA,
  103.                         8 : AGENT_TYPE_YELLOW,
  104.                        }
  105.  
  106. STATUS_BLOCK_UNKNOWN = {'revision' : STATUS_REV_UNKNOWN,
  107.                          'agents' : [],
  108.                          'status-code' : STATUS_UNKNOWN,
  109.                        }
  110.  
  111. NUM_PEN_POS = {STATUS_REV_00 : 16,
  112.                 STATUS_REV_01 : 16,
  113.                 STATUS_REV_02 : 16,
  114.                 STATUS_REV_03 : 18,
  115.                 STATUS_REV_04 : 22}
  116.  
  117. PEN_DATA_SIZE = {STATUS_REV_00 : 8,
  118.                   STATUS_REV_01 : 8,
  119.                   STATUS_REV_02 : 4,
  120.                   STATUS_REV_03 : 8,
  121.                   STATUS_REV_04 : 8}
  122.  
  123. STATUS_POS = {STATUS_REV_00 : 14,
  124.                STATUS_REV_01 : 14,
  125.                STATUS_REV_02 : 14,
  126.                STATUS_REV_03 : 16,
  127.                STATUS_REV_04 : 20}
  128.  
  129. def parseSStatus(s, z=''):
  130.     Z_SIZE = 6
  131.  
  132.     z1 = []
  133.     if len(z) > 0:
  134.         z_fields = z.split(',')
  135.  
  136.         for z_field in z_fields:
  137.  
  138.             if len(z_field) > 2 and z_field[:2] == '05':
  139.                 z1s = z_field[2:]
  140.                 z1 = [int(x, 16) for x in z1s]
  141.  
  142.     s1 = [int(x, 16) for x in s]
  143.  
  144.     revision = s1[1]
  145.  
  146.     assert STATUS_REV_00 <= revision <= STATUS_REV_04
  147.  
  148.     top_door = bool(s1[2] & 0x8L) + s1[2] & 0x1L
  149.     supply_door = bool(s1[3] & 0x8L) + s1[3] & 0x1L
  150.     duplexer = bool(s1[4] & 0xcL) +  s1[4] & 0x1L
  151.     photo_tray = bool(s1[5] & 0x8L) + s1[5] & 0x1L
  152.  
  153.     if revision == STATUS_REV_02:
  154.         in_tray1 = bool(s1[6] & 0x8L) + s1[6] & 0x1L
  155.         in_tray2 = bool(s1[7] & 0x8L) + s1[7] & 0x1L
  156.     else:
  157.         in_tray1 = bool(s1[6] & 0x8L)
  158.         in_tray2 = bool(s1[7] & 0x8L)
  159.  
  160.     media_path = bool(s1[8] & 0x8L) + (s1[8] & 0x1L) + ((bool(s1[18] & 0x2L))<<1)
  161.     status_pos = STATUS_POS[revision]
  162.     status_byte = (s1[status_pos]<<4) + s1[status_pos + 1]
  163.     stat = status_byte + STATUS_PRINTER_BASE
  164.  
  165.     pens, pen, c, d = [], {}, NUM_PEN_POS[revision]+1, 0
  166.     num_pens = s1[NUM_PEN_POS[revision]]
  167.     log.debug("Num pens=%d" % num_pens)
  168.     index = 0
  169.     pen_data_size = PEN_DATA_SIZE[revision]
  170.  
  171.     for p in range(num_pens):
  172.         info = long(s[c : c + pen_data_size], 16)
  173.  
  174.         pen['index'] = index
  175.  
  176.         if pen_data_size == 4:
  177.             pen['type'] = REVISION_2_TYPE_MAP.get(int((info & 0xf000L) >> 12L), 0)
  178.  
  179.             if index < (num_pens / 2):
  180.                 pen['kind'] = AGENT_KIND_HEAD
  181.             else:
  182.                 pen['kind'] = AGENT_KIND_SUPPLY
  183.  
  184.             pen['level-trigger'] = int ((info & 0x0e00L) >> 9L)
  185.             pen['health'] = int((info & 0x0180L) >> 7L)
  186.             pen['level'] = int(info & 0x007fL)
  187.             pen['id'] = 0x1f
  188.  
  189.         elif pen_data_size == 8:
  190.             pen['kind'] = bool(info & 0x80000000L) + ((bool(info & 0x40000000L))<<1L)
  191.             pen['type'] = int((info & 0x3f000000L) >> 24L)
  192.             pen['id'] = int((info & 0xf80000) >> 19L)
  193.             pen['level-trigger'] = int((info & 0x70000L) >> 16L)
  194.             pen['health'] = int((info & 0xc000L) >> 14L)
  195.             pen['level'] = int(info & 0xffL)
  196.  
  197.         else:
  198.             log.error("Pen data size error")
  199.  
  200.         if len(z1) > 0:
  201.             # TODO: Determine cause of IndexError for C6100 (defect #1111)
  202.             try:
  203.                 pen['dvc'] = long(z1s[d+1:d+5], 16)
  204.                 pen['virgin'] = bool(z1[d+5] & 0x8L)
  205.                 pen['hp-ink'] = bool(z1[d+5] & 0x4L)
  206.                 pen['known'] = bool(z1[d+5] & 0x2L)
  207.                 pen['ack'] = bool(z1[d+5] & 0x1L)
  208.             except IndexError:
  209.                 pen['dvc'] = 0
  210.                 pen['virgin'] = 0
  211.                 pen['hp-ink'] = 0
  212.                 pen['known'] = 0
  213.                 pen['ack'] = 0
  214.  
  215.         index += 1
  216.         pens.append(pen)
  217.         pen = {}
  218.         c += pen_data_size
  219.         d += Z_SIZE
  220.  
  221.     return {'revision' :    revision,
  222.              'agents' :      pens,
  223.              'top-door' :    top_door,
  224.              'status-code' : stat,
  225.              'supply-door' : supply_door,
  226.              'duplexer' :    duplexer,
  227.              'photo-tray' :  photo_tray,
  228.              'in-tray1' :    in_tray1,
  229.              'in-tray2' :    in_tray2,
  230.              'media-path' :  media_path,
  231.            }
  232.  
  233.  
  234.  
  235. # $HB0$NC0,ff,DN,IDLE,CUT,K0,C0,DP,NR,KP092,CP041
  236. #     0    1  2  3    4   5  6  7  8  9     10
  237. def parseVStatus(s):
  238.     pens, pen, c = [], {}, 0
  239.     fields = s.split(',')
  240.     log.debug(fields)
  241.     f0 = fields[0]
  242.  
  243.     if len(f0) == 20:
  244.         # TODO: $H00000000$M00000000 style (OJ Pro 1150/70)
  245.         # Need spec
  246.         pass
  247.     elif len(f0) == 8:
  248.         for p in f0:
  249.             if c == 0:
  250.                 #assert p == '$'
  251.                 c += 1
  252.             elif c == 1:
  253.                 if p in ('a', 'A'):
  254.                     pen['type'], pen['kind'] = AGENT_TYPE_NONE, AGENT_KIND_NONE
  255.                 c += 1
  256.             elif c == 2:
  257.                 pen['health'] = AGENT_HEALTH_OK
  258.                 pen['kind'] = AGENT_KIND_HEAD_AND_SUPPLY
  259.                 if   p in ('b', 'B'): pen['type'] = AGENT_TYPE_BLACK
  260.                 elif p in ('c', 'C'): pen['type'] = AGENT_TYPE_CMY
  261.                 elif p in ('d', 'D'): pen['type'] = AGENT_TYPE_KCM
  262.                 elif p in ('u', 'U'): pen['type'], pen['health'] = AGENT_TYPE_NONE, AGENT_HEALTH_MISINSTALLED
  263.                 c += 1
  264.             elif c == 3:
  265.                 if p == '0': pen['state'] = 1
  266.                 else: pen['state'] = 0
  267.  
  268.                 pen['level'] = 0
  269.                 i = 8
  270.  
  271.                 while True:
  272.                     try:
  273.                         f = fields[i]
  274.                     except IndexError:
  275.                         break
  276.                     else:
  277.                         if f[:2] == 'KP' and pen['type'] == AGENT_TYPE_BLACK:
  278.                             pen['level'] = int(f[2:])
  279.                         elif f[:2] == 'CP' and pen['type'] == AGENT_TYPE_CMY:
  280.                             pen['level'] = int(f[2:])
  281.                     i += 1
  282.  
  283.                 pens.append(pen)
  284.                 pen = {}
  285.                 c = 0
  286.     else:
  287.         pass
  288.  
  289.     try:
  290.         fields[2]
  291.     except IndexError: 
  292.         top_lid = 1 # something went wrong!
  293.     else:
  294.         if fields[2] == 'DN':
  295.             top_lid = 1
  296.         else:
  297.             top_lid = 2
  298.  
  299.     try:
  300.         stat = vstatus_xlate.get(fields[3].lower(), STATUS_PRINTER_IDLE)
  301.     except IndexError:
  302.         stat = STATUS_PRINTER_IDLE # something went wrong!
  303.  
  304.     return {'revision' :   STATUS_REV_V,
  305.              'agents' :     pens,
  306.              'top-lid' :    top_lid,
  307.              'status-code': stat,
  308.              'supply-lid' : SUPPLY_DOOR_NOT_PRESENT,
  309.              'duplexer' :   DUPLEXER_NOT_PRESENT,
  310.              'photo-tray' : PHOTO_TRAY_NOT_PRESENT,
  311.              'in-tray1' :   IN_TRAY_NOT_PRESENT,
  312.              'in-tray2' :   IN_TRAY_NOT_PRESENT,
  313.              'media-path' : MEDIA_PATH_CUT_SHEET, # ?
  314.            }
  315.            
  316.  
  317. def parseStatus(DeviceID):
  318.     if 'VSTATUS' in DeviceID:
  319.          return parseVStatus(DeviceID['VSTATUS'])
  320.     elif 'S' in DeviceID:
  321.         return parseSStatus(DeviceID['S'], DeviceID.get('Z', ''))
  322.     else:
  323.         return STATUS_BLOCK_UNKNOWN
  324.  
  325.  
  326.  
  327. def LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state):
  328.     stat = STATUS_PRINTER_IDLE
  329.  
  330.     if device_status in (pml.DEVICE_STATUS_WARNING, pml.DEVICE_STATUS_DOWN):
  331.  
  332.         if detected_error_state & pml.DETECTED_ERROR_STATE_LOW_PAPER_MASK and \
  333.             not (detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK):
  334.             stat = STATUS_PRINTER_LOW_PAPER
  335.  
  336.         elif detected_error_state & pml.DETECTED_ERROR_STATE_NO_PAPER_MASK:
  337.             stat = STATUS_PRINTER_OUT_OF_PAPER
  338.  
  339.         elif detected_error_state & pml.DETECTED_ERROR_STATE_DOOR_OPEN_MASK:
  340.             stat = STATUS_PRINTER_DOOR_OPEN
  341.  
  342.         elif detected_error_state & pml.DETECTED_ERROR_STATE_JAMMED_MASK:
  343.             stat = STATUS_PRINTER_MEDIA_JAM
  344.  
  345.         elif detected_error_state & pml.DETECTED_ERROR_STATE_OUT_CART_MASK:
  346.             stat = STATUS_PRINTER_NO_TONER
  347.  
  348.         elif detected_error_state & pml.DETECTED_ERROR_STATE_LOW_CART_MASK:
  349.             stat = STATUS_PRINTER_LOW_TONER
  350.  
  351.         elif detected_error_state == pml.DETECTED_ERROR_STATE_SERVICE_REQUEST_MASK:
  352.             stat = STATUS_PRINTER_SERVICE_REQUEST
  353.  
  354.         elif detected_error_state & pml.DETECTED_ERROR_STATE_OFFLINE_MASK:
  355.             stat = STATUS_PRINTER_OFFLINE
  356.  
  357.     else:
  358.  
  359.         if printer_status == pml.PRINTER_STATUS_IDLE:
  360.             stat = STATUS_PRINTER_IDLE
  361.  
  362.         elif printer_status == pml.PRINTER_STATUS_PRINTING:
  363.             stat = STATUS_PRINTER_PRINTING
  364.  
  365.         elif printer_status == pml.PRINTER_STATUS_WARMUP:
  366.             stat = STATUS_PRINTER_WARMING_UP
  367.  
  368.     return stat
  369.  
  370. # Map from ISO 10175/10180 to HPLIP types
  371. COLORANT_INDEX_TO_AGENT_TYPE_MAP = {
  372.                                     'other' :   AGENT_TYPE_UNSPECIFIED,
  373.                                     'unknown' : AGENT_TYPE_UNSPECIFIED,
  374.                                     'blue' :    AGENT_TYPE_BLUE,
  375.                                     'cyan' :    AGENT_TYPE_CYAN,
  376.                                     'magenta':  AGENT_TYPE_MAGENTA,
  377.                                     'yellow' :  AGENT_TYPE_YELLOW,
  378.                                     'black' :   AGENT_TYPE_BLACK,
  379.                                    }
  380.  
  381. MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP = {
  382.     pml.OID_MARKER_SUPPLIES_TYPE_OTHER :              AGENT_KIND_UNKNOWN,
  383.     pml.OID_MARKER_SUPPLIES_TYPE_UNKNOWN :            AGENT_KIND_UNKNOWN,
  384.     pml.OID_MARKER_SUPPLIES_TYPE_TONER :              AGENT_KIND_TONER_CARTRIDGE,
  385.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_TONER :        AGENT_KIND_UNKNOWN,
  386.     pml.OID_MARKER_SUPPLIES_TYPE_INK :                AGENT_KIND_SUPPLY,
  387.     pml.OID_MARKER_SUPPLIES_TYPE_INK_CART :           AGENT_KIND_HEAD_AND_SUPPLY,
  388.     pml.OID_MARKER_SUPPLIES_TYPE_INK_RIBBON :         AGENT_KIND_HEAD_AND_SUPPLY,
  389.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_INK :          AGENT_KIND_UNKNOWN,
  390.     pml.OID_MARKER_SUPPLIES_TYPE_OPC :                AGENT_KIND_DRUM_KIT,
  391.     pml.OID_MARKER_SUPPLIES_TYPE_DEVELOPER :          AGENT_KIND_UNKNOWN,
  392.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL :          AGENT_KIND_UNKNOWN,
  393.     pml.OID_MARKER_SUPPLIES_TYPE_SOLID_WAX :          AGENT_KIND_UNKNOWN,
  394.     pml.OID_MARKER_SUPPLIES_TYPE_RIBBON_WAX :         AGENT_KIND_UNKNOWN,
  395.     pml.OID_MARKER_SUPPLIES_TYPE_WASTE_WAX :          AGENT_KIND_UNKNOWN,
  396.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER :              AGENT_KIND_MAINT_KIT,
  397.     pml.OID_MARKER_SUPPLIES_TYPE_CORONA_WIRE :        AGENT_KIND_UNKNOWN,
  398.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OIL_WICK :     AGENT_KIND_UNKNOWN,
  399.     pml.OID_MARKER_SUPPLIES_TYPE_CLEANER_UNIT :       AGENT_KIND_UNKNOWN,
  400.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_CLEANING_PAD : AGENT_KIND_UNKNOWN,
  401.     pml.OID_MARKER_SUPPLIES_TYPE_TRANSFER_UNIT :      AGENT_KIND_TRANSFER_KIT,
  402.     pml.OID_MARKER_SUPPLIES_TYPE_TONER_CART :         AGENT_KIND_TONER_CARTRIDGE,
  403.     pml.OID_MARKER_SUPPLIES_TYPE_FUSER_OILER :        AGENT_KIND_UNKNOWN,
  404.     pml.OID_MARKER_SUPPLIES_TYPE_ADF_MAINT_KIT :      AGENT_KIND_ADF_KIT,
  405. }
  406.  
  407.  
  408. def StatusType3( dev, parsedID ): # LaserJet Status (PML/SNMP)
  409.     try:
  410.         dev.openPML()
  411.         #result_code, on_off_line = dev.getPML( pml.OID_ON_OFF_LINE, pml.INT_SIZE_BYTE )
  412.         #result_code, sleep_mode = dev.getPML( pml.OID_SLEEP_MODE, pml.INT_SIZE_BYTE )
  413.         result_code, printer_status = dev.getPML( pml.OID_PRINTER_STATUS, pml.INT_SIZE_BYTE )
  414.         result_code, device_status = dev.getPML( pml.OID_DEVICE_STATUS, pml.INT_SIZE_BYTE )
  415.         result_code, cover_status = dev.getPML( pml.OID_COVER_STATUS, pml.INT_SIZE_BYTE )
  416.         result_code, value = dev.getPML( pml.OID_DETECTED_ERROR_STATE )
  417.     except Error:
  418.        dev.closePML()
  419.  
  420.        return {'revision' :    STATUS_REV_UNKNOWN,
  421.                  'agents' :      [],
  422.                  'top-door' :    0,
  423.                  'status-code' : STATUS_UNKNOWN,
  424.                  'supply-door' : 0,
  425.                  'duplexer' :    1,
  426.                  'photo-tray' :  0,
  427.                  'in-tray1' :    0,
  428.                  'in-tray2' :    0,
  429.                  'media-path' :  0,
  430.                }
  431.  
  432.     try:
  433.         detected_error_state = struct.unpack( 'B', value[0])[0]
  434.     except (IndexError, TypeError):
  435.         detected_error_state = pml.DETECTED_ERROR_STATE_OFFLINE_MASK
  436.  
  437.     agents, x = [], 1
  438.  
  439.     while True:
  440.         log.debug( "%s Agent: %d %s" % ("*"*10, x, "*"*10))
  441.         log.debug("OID_MARKER_SUPPLIES_TYPE_%d:" % x)
  442.         oid = ( pml.OID_MARKER_SUPPLIES_TYPE_x % x, pml.OID_MARKER_SUPPLIES_TYPE_x_TYPE )
  443.         result_code, value = dev.getPML( oid, pml.INT_SIZE_BYTE )
  444.  
  445.         if result_code != ERROR_SUCCESS or value is None:
  446.             log.debug("End of supply information.")
  447.             break
  448.  
  449.         for a in MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP:
  450.             if value == a:
  451.                 agent_kind = MARKER_SUPPLES_TYPE_TO_AGENT_KIND_MAP[a]
  452.                 break
  453.         else:
  454.             agent_kind = AGENT_KIND_UNKNOWN
  455.  
  456.         # TODO: Deal with printers that return -1 and -2 for level and max (LJ3380)
  457.  
  458.         log.debug("OID_MARKER_SUPPLIES_LEVEL_%d:" % x)
  459.         oid = ( pml.OID_MARKER_SUPPLIES_LEVEL_x % x, pml.OID_MARKER_SUPPLIES_LEVEL_x_TYPE )
  460.         result_code, agent_level = dev.getPML( oid )
  461.  
  462.         if result_code != ERROR_SUCCESS:
  463.             log.debug("Failed")
  464.             break
  465.  
  466.         log.debug( 'agent%d-level: %d' % ( x, agent_level ) )
  467.         log.debug("OID_MARKER_SUPPLIES_MAX_%d:" % x)
  468.         oid = ( pml.OID_MARKER_SUPPLIES_MAX_x % x, pml.OID_MARKER_SUPPLIES_MAX_x_TYPE )
  469.         result_code, agent_max = dev.getPML( oid )
  470.  
  471.         if agent_max == 0: agent_max = 1
  472.  
  473.         if result_code != ERROR_SUCCESS:
  474.             log.debug("Failed")
  475.             break
  476.  
  477.         log.debug( 'agent%d-max: %d' % ( x, agent_max ) )
  478.         log.debug("OID_MARKER_SUPPLIES_COLORANT_INDEX_%d:" % x)
  479.         oid = ( pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x % x, pml.OID_MARKER_SUPPLIES_COLORANT_INDEX_x_TYPE )
  480.         result_code, colorant_index = dev.getPML( oid )
  481.  
  482.         if result_code != ERROR_SUCCESS: # 3080, 3055 will fail here
  483.             log.debug("Failed")
  484.             agent_type = AGENT_TYPE_BLACK
  485.             #break
  486.         else:
  487.             log.debug("Colorant index: %d" % colorant_index)
  488.  
  489.             log.debug("OID_MARKER_COLORANT_VALUE_%d" % x)
  490.             oid = ( pml.OID_MARKER_COLORANT_VALUE_x % colorant_index, pml.OID_MARKER_COLORANT_VALUE_x_TYPE )
  491.             result_code, colorant_value = dev.getPML( oid )
  492.  
  493.             if result_code != ERROR_SUCCESS:
  494.                 log.debug("Failed. Defaulting to black.")
  495.                 agent_type = AGENT_TYPE_BLACK
  496.             #else:
  497.             if 1:
  498.                 if agent_kind in (AGENT_KIND_MAINT_KIT, AGENT_KIND_ADF_KIT,
  499.                                   AGENT_KIND_DRUM_KIT, AGENT_KIND_TRANSFER_KIT):
  500.  
  501.                     agent_type = AGENT_TYPE_UNSPECIFIED
  502.  
  503.                 else:
  504.                     agent_type = AGENT_TYPE_BLACK
  505.  
  506.                     if result_code != ERROR_SUCCESS:
  507.                         log.debug("OID_MARKER_SUPPLIES_DESCRIPTION_%d:" % x)
  508.                         oid = (pml.OID_MARKER_SUPPLIES_DESCRIPTION_x % x, pml.OID_MARKER_SUPPLIES_DESCRIPTION_x_TYPE)
  509.                         result_code, colorant_value = dev.getPML( oid )
  510.  
  511.                         if result_code != ERROR_SUCCESS:
  512.                             log.debug("Failed")
  513.                             break
  514.  
  515.                         if colorant_value is not None:
  516.                             log.debug("colorant value: %s" % colorant_value)
  517.                             colorant_value = colorant_value.lower().strip()
  518.  
  519.                             for c in COLORANT_INDEX_TO_AGENT_TYPE_MAP:
  520.                                 if colorant_value.find(c) >= 0:
  521.                                     agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP[c]
  522.                                     break
  523.                             else:
  524.                                 agent_type = AGENT_TYPE_BLACK
  525.  
  526.                     else: # SUCCESS
  527.                         if colorant_value is not None:
  528.                             log.debug("colorant value: %s" % colorant_value)
  529.                             agent_type = COLORANT_INDEX_TO_AGENT_TYPE_MAP.get( colorant_value, AGENT_TYPE_BLACK )
  530.  
  531.                         if agent_type == AGENT_TYPE_NONE:
  532.                             if agent_kind == AGENT_KIND_TONER_CARTRIDGE:
  533.                                 agent_type = AGENT_TYPE_BLACK
  534.                             else:
  535.                                 agent_type = AGENT_TYPE_UNSPECIFIED
  536.  
  537.         log.debug("OID_MARKER_STATUS_%d:" % x)
  538.         oid = ( pml.OID_MARKER_STATUS_x % x, pml.OID_MARKER_STATUS_x_TYPE )
  539.         result_code, agent_status = dev.getPML( oid )
  540.  
  541.         if result_code != ERROR_SUCCESS:
  542.             log.debug("Failed")
  543.             agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  544.             agent_health = AGENT_HEALTH_OK
  545.         else:
  546.             agent_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  547.  
  548.             if agent_status is None:
  549.                 agent_health = AGENT_HEALTH_OK
  550.  
  551.             elif agent_status == pml.OID_MARKER_STATUS_OK:
  552.                 agent_health = AGENT_HEALTH_OK
  553.  
  554.             elif agent_status == pml.OID_MARKER_STATUS_MISINSTALLED:
  555.                 agent_health = AGENT_HEALTH_MISINSTALLED
  556.  
  557.             elif agent_status in ( pml.OID_MARKER_STATUS_LOW_TONER_CONT,
  558.                                    pml.OID_MARKER_STATUS_LOW_TONER_STOP ):
  559.  
  560.                 agent_health = AGENT_HEALTH_OK
  561.                 agent_trigger = AGENT_LEVEL_TRIGGER_MAY_BE_LOW
  562.  
  563.             else:
  564.                 agent_health = AGENT_HEALTH_OK
  565.  
  566.         agent_level = int(agent_level/agent_max * 100)
  567.  
  568.         log.debug("agent%d: kind=%d, type=%d, health=%d, level=%d, level-trigger=%d" % \
  569.             (x, agent_kind, agent_type, agent_health, agent_level, agent_trigger))
  570.  
  571.  
  572.         agents.append({'kind' : agent_kind,
  573.                        'type' : agent_type,
  574.                        'health' : agent_health,
  575.                        'level' : agent_level,
  576.                        'level-trigger' : agent_trigger,})
  577.  
  578.         x += 1
  579.  
  580.         if x > 20:
  581.             break
  582.  
  583.  
  584.     printer_status = printer_status or STATUS_PRINTER_IDLE
  585.     log.debug("printer_status=%d" % printer_status)
  586.     device_status = device_status or pml.DEVICE_STATUS_RUNNING
  587.     log.debug("device_status=%d" % device_status)
  588.     cover_status = cover_status or pml.COVER_STATUS_CLOSED
  589.     log.debug("cover_status=%d" % cover_status)
  590.     detected_error_state = detected_error_state or pml.DETECTED_ERROR_STATE_NO_ERROR
  591.     log.debug("detected_error_state=%d (0x%x)" % (detected_error_state, detected_error_state))
  592.  
  593.     stat = LaserJetDeviceStatusToPrinterStatus(device_status, printer_status, detected_error_state)
  594.  
  595.     log.debug("Printer status=%d" % stat)
  596.  
  597.     if stat == STATUS_PRINTER_DOOR_OPEN:
  598.         supply_door = 0
  599.     else:
  600.         supply_door = 1
  601.  
  602.     return {'revision' :    STATUS_REV_UNKNOWN,
  603.              'agents' :      agents,
  604.              'top-door' :    cover_status,
  605.              'status-code' : stat,
  606.              'supply-door' : supply_door,
  607.              'duplexer' :    1,
  608.              'photo-tray' :  0,
  609.              'in-tray1' :    1,
  610.              'in-tray2' :    1,
  611.              'media-path' :  1,
  612.            }
  613.  
  614. def setup_panel_translator():
  615.     printables = list(
  616. """0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
  617. !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~""")
  618.  
  619.     map = {}
  620.     for x in [chr(x) for x in range(0,256)]:
  621.         if x in printables:
  622.             map[x] = x
  623.         else:
  624.             map[x] = '\x20'
  625.  
  626.     map.update({'\x10' : '\xab',
  627.                     '\x11' : '\xbb',
  628.                     '\x12' : '\xa3',
  629.                     '\x13' : '\xbb',
  630.                     '\x80' : '\xab',
  631.                     '\x81' : '\xbb',
  632.                     '\x82' : '\x2a',
  633.                     '\x83' : '\x2a',
  634.                     '\x85' : '\x2a',
  635.                     '\xa0' : '\xab',
  636.                     '\x1f' : '\x3f',
  637.                     '='    : '\x20',
  638.                 })
  639.  
  640.     frm, to = '', ''
  641.     map_keys = map.keys()
  642.     map_keys.sort()
  643.     for x in map_keys:
  644.         frm = ''.join([frm, x])
  645.         to = ''.join([to, map[x]])
  646.  
  647.     global PANEL_TRANSLATOR_FUNC
  648.     PANEL_TRANSLATOR_FUNC = utils.Translator(frm, to)
  649.  
  650. PANEL_TRANSLATOR_FUNC = None
  651. setup_panel_translator()
  652.  
  653.  
  654. def PanelCheck(dev):
  655.     line1, line2 = '', ''
  656.     
  657.     if dev.io_mode not in (IO_MODE_RAW, IO_MODE_UNI):
  658.     
  659.         try:
  660.             dev.openPML()
  661.         except Error:
  662.             pass
  663.         else:
  664.  
  665.             oids = [(pml.OID_HP_LINE1, pml.OID_HP_LINE2),
  666.                      (pml.OID_SPM_LINE1, pml.OID_SPM_LINE2)]
  667.  
  668.             for oid1, oid2 in oids:
  669.                 result, line1 = dev.getPML(oid1)
  670.  
  671.                 if result < pml.ERROR_MAX_OK:
  672.                     line1 = PANEL_TRANSLATOR_FUNC(line1).rstrip()
  673.  
  674.                     if '\x0a' in line1:
  675.                         line1, line2 = line1.split('\x0a', 1)
  676.                         break
  677.  
  678.                     result, line2 = dev.getPML(oid2)
  679.  
  680.                     if result < pml.ERROR_MAX_OK:
  681.                         line2 = PANEL_TRANSLATOR_FUNC(line2).rstrip()
  682.                         break
  683.  
  684.     return bool(line1 or line2), line1 or '', line2 or ''
  685.  
  686.  
  687. BATTERY_HEALTH_MAP = {0 : AGENT_HEALTH_OK,
  688.                        1 : AGENT_HEALTH_OVERTEMP,
  689.                        2 : AGENT_HEALTH_CHARGING,
  690.                        3 : AGENT_HEALTH_MISINSTALLED,
  691.                        4 : AGENT_HEALTH_FAILED,
  692.                       }
  693.  
  694.  
  695. BATTERY_TRIGGER_MAP = {0 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  696.                         1 : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  697.                         2 : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
  698.                         3 : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
  699.                         4 : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
  700.                         5 : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  701.                        }
  702.  
  703. BATTERY_PML_TRIGGER_MAP = {
  704.         (100, 80)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  705.         (79,  60)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_1,
  706.         (59,  40)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_2,
  707.         (39,  30)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_3,
  708.         (29,  20)  : AGENT_LEVEL_TRIGGER_SUFFICIENT_4,
  709.         (19,  10)  : AGENT_LEVEL_TRIGGER_MAY_BE_LOW,
  710.         (9,    5)  : AGENT_LEVEL_TRIGGER_PROBABLY_OUT,
  711.         (4,   -1)  : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  712.         }
  713.  
  714.  
  715. def BatteryCheck(dev, status_block, battery_check):
  716.     try_dynamic_counters = False
  717.  
  718.     try:
  719.         try:
  720.             dev.openPML()
  721.         except Error:
  722.             if battery_check == STATUS_BATTERY_CHECK_STD:
  723.                 log.debug("PML channel open failed. Trying dynamic counters...")
  724.                 try_dynamic_counters = True
  725.         else:
  726.             if battery_check == STATUS_BATTERY_CHECK_PML:
  727.                 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL_2)
  728.                 
  729.                 if result > pml.ERROR_MAX_OK:
  730.                     status_block['agents'].append({
  731.                         'kind'   : AGENT_KIND_INT_BATTERY,
  732.                         'type'   : AGENT_TYPE_UNSPECIFIED,
  733.                         'health' : AGENT_HEALTH_UNKNOWN,
  734.                         'level'  : 0,
  735.                         'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  736.                         })
  737.                     return
  738.                 
  739.                 else:
  740.                     status_block['agents'].append({
  741.                         'kind'   : AGENT_KIND_INT_BATTERY,
  742.                         'type'   : AGENT_TYPE_UNSPECIFIED,
  743.                         'health' : AGENT_HEALTH_OK,
  744.                         'level'  : battery_level,
  745.                         'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  746.                         })
  747.                     return
  748.             
  749.             else: # STATUS_BATTERY_CHECK_STD
  750.                 result, battery_level = dev.getPML(pml.OID_BATTERY_LEVEL)
  751.                 result, power_mode =  dev.getPML(pml.OID_POWER_MODE)
  752.  
  753.                 if battery_level is not None and \
  754.                     power_mode is not None:
  755.  
  756.                     if power_mode & pml.POWER_MODE_BATTERY_LEVEL_KNOWN and \
  757.                         battery_level >= 0:
  758.  
  759.                         for x in BATTERY_PML_TRIGGER_MAP:
  760.                             if x[0] >= battery_level > x[1]:
  761.                                 battery_trigger_level = BATTERY_PML_TRIGGER_MAP[x]
  762.                                 break
  763.  
  764.                         if power_mode & pml.POWER_MODE_CHARGING:
  765.                             agent_health = AGENT_HEALTH_CHARGING
  766.  
  767.                         elif power_mode & pml.POWER_MODE_DISCHARGING:
  768.                             agent_health = AGENT_HEALTH_DISCHARGING
  769.  
  770.                         else:
  771.                             agent_health = AGENT_HEALTH_OK
  772.  
  773.                         status_block['agents'].append({
  774.                             'kind'   : AGENT_KIND_INT_BATTERY,
  775.                             'type'   : AGENT_TYPE_UNSPECIFIED,
  776.                             'health' : agent_health,
  777.                             'level'  : battery_level,
  778.                             'level-trigger' : battery_trigger_level,
  779.                             })
  780.                         return
  781.                         
  782.                     else:
  783.                         status_block['agents'].append({
  784.                             'kind'   : AGENT_KIND_INT_BATTERY,
  785.                             'type'   : AGENT_TYPE_UNSPECIFIED,
  786.                             'health' : AGENT_HEALTH_UNKNOWN,
  787.                             'level'  : 0,
  788.                             'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  789.                             })
  790.                         return
  791.  
  792.                 else:
  793.                     try_dynamic_counters = True
  794.  
  795.     finally:
  796.         dev.closePML()
  797.  
  798.     
  799.     if battery_check == STATUS_BATTERY_CHECK_STD and \
  800.         try_dynamic_counters:
  801.  
  802.         try:
  803.             try:
  804.                 battery_health = dev.getDynamicCounter(200)
  805.                 battery_trigger_level = dev.getDynamicCounter(201)
  806.                 battery_level = dev.getDynamicCounter(202)
  807.  
  808.                 status_block['agents'].append({
  809.                     'kind'   : AGENT_KIND_INT_BATTERY,
  810.                     'type'   : AGENT_TYPE_UNSPECIFIED,
  811.                     'health' : BATTERY_HEALTH_MAP[battery_health],
  812.                     'level'  : battery_level,
  813.                     'level-trigger' : BATTERY_TRIGGER_MAP[battery_trigger_level],
  814.                     })
  815.             except Error:
  816.                 status_block['agents'].append({
  817.                     'kind'   : AGENT_KIND_INT_BATTERY,
  818.                     'type'   : AGENT_TYPE_UNSPECIFIED,
  819.                     'health' : AGENT_HEALTH_UNKNOWN,
  820.                     'level'  : 0,
  821.                     'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  822.                     })
  823.         finally:
  824.             dev.closePrint()
  825.             
  826.     else:
  827.         status_block['agents'].append({
  828.             'kind'   : AGENT_KIND_INT_BATTERY,
  829.             'type'   : AGENT_TYPE_UNSPECIFIED,
  830.             'health' : AGENT_HEALTH_UNKNOWN,
  831.             'level'  : 0,
  832.             'level-trigger' : AGENT_LEVEL_TRIGGER_SUFFICIENT_0,
  833.             })
  834.         
  835.  
  836.  
  837. # this works for 2 pen products that allow 1 or 2 pens inserted
  838. # from: k, kcm, cmy, ggk
  839. def getPenConfiguration(s): # s=status dict from parsed device ID
  840.     pens = [p['type'] for p in s['agents']]
  841.  
  842.     if utils.all(pens, lambda x : x==AGENT_TYPE_NONE):
  843.         return AGENT_CONFIG_NONE
  844.  
  845.     if AGENT_TYPE_NONE in pens:
  846.  
  847.         if AGENT_TYPE_BLACK in pens:
  848.             return AGENT_CONFIG_BLACK_ONLY
  849.  
  850.         elif AGENT_TYPE_CMY in pens:
  851.             return AGENT_CONFIG_COLOR_ONLY
  852.  
  853.         elif AGENT_TYPE_KCM in pens:
  854.             return AGENT_CONFIG_PHOTO_ONLY
  855.  
  856.         elif AGENT_TYPE_GGK in pens:
  857.             return AGENT_CONFIG_GREY_ONLY
  858.  
  859.         else:
  860.             return AGENT_CONFIG_INVALID
  861.  
  862.     else:
  863.         if AGENT_TYPE_BLACK in pens and AGENT_TYPE_CMY in pens:
  864.             return AGENT_CONFIG_COLOR_AND_BLACK
  865.  
  866.         elif AGENT_TYPE_CMY in pens and AGENT_TYPE_KCM in pens:
  867.             return AGENT_CONFIG_COLOR_AND_PHOTO
  868.  
  869.         elif AGENT_TYPE_CMY in pens and AGENT_TYPE_GGK in pens:
  870.             return AGENT_CONFIG_COLOR_AND_GREY
  871.  
  872.         else:
  873.             return AGENT_CONFIG_INVALID
  874.  
  875.  
  876. def getFaxStatus(dev):
  877.     tx_active, rx_active = False, False
  878.     
  879.     if dev.io_mode not in (IO_MODE_UNI, IO_MODE_RAW):
  880.         try:
  881.             dev.openPML()
  882.  
  883.             result_code, tx_state = dev.getPML(pml.OID_FAXJOB_TX_STATUS)
  884.  
  885.             if result_code == ERROR_SUCCESS and tx_state:
  886.                 if tx_state not in (pml.FAXJOB_TX_STATUS_IDLE, pml.FAXJOB_TX_STATUS_DONE):
  887.                     tx_active = True
  888.  
  889.             result_code, rx_state = dev.getPML(pml.OID_FAXJOB_RX_STATUS)
  890.  
  891.             if result_code == ERROR_SUCCESS and rx_state:
  892.                 if rx_state not in (pml.FAXJOB_RX_STATUS_IDLE, pml.FAXJOB_RX_STATUS_DONE):
  893.                     rx_active = True
  894.  
  895.         finally:
  896.             dev.closePML()
  897.  
  898.     return tx_active, rx_active
  899.     
  900.   
  901.  
  902.  
  903. TYPE6_STATUS_CODE_MAP = {
  904.      0    : STATUS_PRINTER_IDLE, #</DevStatusUnknown>
  905.     -19928: STATUS_PRINTER_IDLE,
  906.     -18995: STATUS_PRINTER_CANCELING,
  907.     -17974: STATUS_PRINTER_WARMING_UP,
  908.     -17973: STATUS_PRINTER_PEN_CLEANING, # sic
  909.     -18993: STATUS_PRINTER_BUSY,
  910.     -17949: STATUS_PRINTER_BUSY,
  911.     -19720: STATUS_PRINTER_MANUAL_DUPLEX_BLOCK,
  912.     -19678: STATUS_PRINTER_BUSY,
  913.     -19695: STATUS_PRINTER_OUT_OF_PAPER,
  914.     -17985: STATUS_PRINTER_MEDIA_JAM,
  915.     -19731: STATUS_PRINTER_OUT_OF_PAPER,
  916.     -18974: STATUS_PRINTER_BUSY, #?
  917.     -19730: STATUS_PRINTER_OUT_OF_PAPER,
  918.     -19729: STATUS_PRINTER_OUT_OF_PAPER,
  919.     -19933: STATUS_PRINTER_HARD_ERROR, # out of memory
  920.     -17984: STATUS_PRINTER_DOOR_OPEN, 
  921.     -19694: STATUS_PRINTER_DOOR_OPEN,
  922.     -18992: STATUS_PRINTER_MANUAL_FEED_BLOCKED, # ?
  923.     -19690: STATUS_PRINTER_MEDIA_JAM, # tray 1
  924.     -19689: STATUS_PRINTER_MEDIA_JAM, # tray 2
  925.     -19611: STATUS_PRINTER_MEDIA_JAM, # tray 3
  926.     -19686: STATUS_PRINTER_MEDIA_JAM,
  927.     -19688: STATUS_PRINTER_MEDIA_JAM, # paper path
  928.     -19685: STATUS_PRINTER_MEDIA_JAM, # cart area
  929.     -19684: STATUS_PRINTER_MEDIA_JAM, # output bin
  930.     -18848: STATUS_PRINTER_MEDIA_JAM, # duplexer
  931.     -18847: STATUS_PRINTER_MEDIA_JAM, # door open
  932.     -18846: STATUS_PRINTER_MEDIA_JAM, # tray 2
  933.     -19687: STATUS_PRINTER_MEDIA_JAM, # open door
  934.     -17992: STATUS_PRINTER_MEDIA_JAM, # mispick
  935.     -19700: STATUS_PRINTER_HARD_ERROR, # invalid driver
  936.     -17996: STATUS_PRINTER_FUSER_ERROR, # fuser error
  937.     -17983: STATUS_PRINTER_FUSER_ERROR,
  938.     -17982: STATUS_PRINTER_FUSER_ERROR,
  939.     -17981: STATUS_PRINTER_FUSER_ERROR,
  940.     -17971: STATUS_PRINTER_FUSER_ERROR,
  941.     -17995: STATUS_PRINTER_HARD_ERROR, # beam error
  942.     -17994: STATUS_PRINTER_HARD_ERROR, # scanner error
  943.     -17993: STATUS_PRINTER_HARD_ERROR, # fan error
  944.     -18994: STATUS_PRINTER_HARD_ERROR,
  945.     -17986: STATUS_PRINTER_HARD_ERROR,
  946.     -19904: STATUS_PRINTER_HARD_ERROR,
  947.     -19701: STATUS_PRINTER_NON_HP_INK, # [sic]
  948.     -19613: STATUS_PRINTER_IDLE, # HP
  949.     -19654: STATUS_PRINTER_NON_HP_INK, # [sic]
  950.     -19682: STATUS_PRINTER_HARD_ERROR, # resinstall
  951.     -19693: STATUS_PRINTER_IDLE, # ?? To Accept
  952.     -19752: STATUS_PRINTER_LOW_TONER,
  953.     -19723: STATUS_PRINTER_BUSY,
  954.     -19703: STATUS_PRINTER_BUSY,
  955.     -19739: STATUS_PRINTER_NO_TONER,
  956.     -19927: STATUS_PRINTER_BUSY,
  957.     -19932: STATUS_PRINTER_BUSY,
  958.     -19931: STATUS_PRINTER_BUSY,
  959.     -11989: STATUS_PRINTER_BUSY,
  960.     -11995: STATUS_PRINTER_BUSY, # ADF loaded
  961.     -19954: STATUS_PRINTER_CANCELING,
  962.     -19955: STATUS_PRINTER_REPORT_PRINTING,
  963.     -19956: STATUS_PRINTER_REPORT_PRINTING,
  964.     -19934: STATUS_PRINTER_HARD_ERROR,
  965.     -19930: STATUS_PRINTER_BUSY,
  966.     -11990: STATUS_PRINTER_DOOR_OPEN,
  967.     -11999: STATUS_PRINTER_MEDIA_JAM, # ADF
  968.     -12000: STATUS_PRINTER_MEDIA_JAM, # ADF
  969.     -11998: STATUS_PRINTER_MEDIA_JAM, # ADF
  970.     -11986: STATUS_PRINTER_HARD_ERROR, # scanner
  971.     -11994: STATUS_PRINTER_BUSY,
  972.     -14967: STATUS_PRINTER_BUSY,
  973.     -19912: STATUS_PRINTER_HARD_ERROR,
  974.     -14962: STATUS_PRINTER_BUSY, # copy pending
  975.     -14971: STATUS_PRINTER_BUSY, # copying
  976.     -14973: STATUS_PRINTER_BUSY, # copying being canceled
  977.     -14972: STATUS_PRINTER_BUSY, # copying canceled
  978.     -14966: STATUS_PRINTER_DOOR_OPEN,
  979.     -14974: STATUS_PRINTER_MEDIA_JAM,
  980.     -14969: STATUS_PRINTER_HARD_ERROR,
  981.     -14968: STATUS_PRINTER_HARD_ERROR,
  982.     -12996: STATUS_PRINTER_BUSY, # scan
  983.     -12994: STATUS_PRINTER_BUSY, # scan
  984.     -12993: STATUS_PRINTER_BUSY, # scan
  985.     -12991: STATUS_PRINTER_BUSY, # scan
  986.     -12995: STATUS_PRINTER_BUSY, # scan
  987.     -12997: STATUS_PRINTER_HARD_ERROR, # scan
  988.     -12990: STATUS_PRINTER_BUSY,
  989.     -12998: STATUS_PRINTER_BUSY,
  990.     -13000: STATUS_PRINTER_DOOR_OPEN,
  991.     -12999: STATUS_PRINTER_MEDIA_JAM,
  992.     -13859: STATUS_PRINTER_BUSY,
  993.     -13858: STATUS_PRINTER_BUSY, #</DevStatusDialingOut>
  994.     -13868: STATUS_PRINTER_BUSY, #</DevStatusRedialPending>
  995.     -13867: STATUS_PRINTER_BUSY, #</DevStatusFaxSendCanceled>
  996.     -13857: STATUS_PRINTER_BUSY, #</DevStatusConnecting>
  997.     -13856: STATUS_PRINTER_BUSY, #</DevStatusSendingPage>
  998.     -13855: STATUS_PRINTER_BUSY, #</DevStatusOnePageSend>
  999.     -13854: STATUS_PRINTER_BUSY, #</DevStatusMultiplePagesSent>
  1000.     -13853: STATUS_PRINTER_BUSY, #</DevStatusSenderCancelingFax>
  1001.     -13839: STATUS_PRINTER_BUSY, #</DevStatusIncomingCall>
  1002.     -13842: STATUS_PRINTER_BUSY, #</DevStatusBlockingFax>
  1003.     -13838: STATUS_PRINTER_BUSY, #</DevStatusReceivingFax>
  1004.     -13847: STATUS_PRINTER_BUSY, #</DevStatusSinglePageReceived>
  1005.     -13846: STATUS_PRINTER_BUSY, #</DevStatusDoublePagesReceived>
  1006.     -13845: STATUS_PRINTER_BUSY, #</DevStatusTriplePagesReceived>
  1007.     -13844: STATUS_PRINTER_BUSY, #</DevStatusPrintingFax>
  1008.     -13840: STATUS_PRINTER_BUSY, #</DevStatusCancelingFaxPrint>
  1009.     -13843: STATUS_PRINTER_BUSY, #</DevStatusFaxCancelingReceive>
  1010.     -13850: STATUS_PRINTER_BUSY, #</DevStatusFaxCanceledReceive>
  1011.     -13851: STATUS_PRINTER_BUSY, #</DevStatusFaxDelayedSendMemoryFull>
  1012.     -13836: STATUS_PRINTER_BUSY, #</DevStatusNoDialTone>
  1013.     -13864: STATUS_PRINTER_BUSY, #</DevStatusNoFaxAnswer>
  1014.     -13863: STATUS_PRINTER_BUSY, #</DevStatusFaxBusy>
  1015.     -13865: STATUS_PRINTER_BUSY, #</DevStatusNoDocumentSent>
  1016.     -13862: STATUS_PRINTER_BUSY, #</DevStatusFaxSendError>
  1017.     -13837: STATUS_PRINTER_BUSY, #</DevStatusT30Error>
  1018.     -13861: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullSend>
  1019.     -13866: STATUS_PRINTER_BUSY, #</DevStatusADFNotCleared>
  1020.     -13841: STATUS_PRINTER_BUSY, #</DevStatusNoFaxDetected>
  1021.     -13848: STATUS_PRINTER_BUSY, #</DevStatusFaxMemoryFullReceive>
  1022.     -13849: STATUS_PRINTER_BUSY, #</DevStatusFaxReceiveError>
  1023.  
  1024. }    
  1025.  
  1026. def StatusType6(dev): #  LaserJet Status (XML)
  1027.     info_device_status = cStringIO.StringIO()
  1028.     info_ssp = cStringIO.StringIO()
  1029.  
  1030.     dev.getEWSUrl("/hp/device/info_device_status.xml", info_device_status)
  1031.     dev.getEWSUrl("/hp/device/info_ssp.xml", info_ssp)
  1032.  
  1033.     info_device_status = info_device_status.getvalue()
  1034.     info_ssp = info_ssp.getvalue()
  1035.  
  1036.     device_status = {}
  1037.     ssp = {}
  1038.  
  1039.     if info_device_status:
  1040.         try:
  1041.             device_status = utils.XMLToDictParser().parseXML(info_device_status)
  1042.             log.debug_block("info_device_status", info_device_status)
  1043.             log.debug(device_status)
  1044.         except expat.ExpatError:
  1045.             log.error("Device Status XML parse error")
  1046.             device_status = {}
  1047.  
  1048.     if info_ssp:
  1049.         try:
  1050.             ssp = utils.XMLToDictParser().parseXML(info_ssp)
  1051.             log.debug_block("info_spp", info_ssp)
  1052.             log.debug(ssp)
  1053.         except expat.ExpatError:
  1054.             log.error("SSP XML parse error")            
  1055.             ssp = {}
  1056.  
  1057.     status_code = device_status.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
  1058.  
  1059.     if not status_code:
  1060.         status_code = ssp.get('devicestatuspage-devicestatus-statuslist-status-code-0', 0)
  1061.  
  1062.     black_supply_level = device_status.get('devicestatuspage-suppliesstatus-blacksupply-percentremaining', 0)
  1063.     black_supply_low = ssp.get('suppliesstatuspage-blacksupply-lowreached', 0)
  1064.     agents = []
  1065.  
  1066.     agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1067.                      'type' : AGENT_TYPE_BLACK,
  1068.                      'health' : 0,
  1069.                      'level' : black_supply_level,
  1070.                      'level-trigger' : 0,
  1071.                   })
  1072.  
  1073.     if dev.tech_type == TECH_TYPE_COLOR_LASER:
  1074.         cyan_supply_level = device_status.get('devicestatuspage-suppliesstatus-cyansupply-percentremaining', 0)
  1075.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1076.                          'type' : AGENT_TYPE_CYAN,
  1077.                          'health' : 0,
  1078.                          'level' : cyan_supply_level,
  1079.                          'level-trigger' : 0,
  1080.                       })
  1081.  
  1082.         magenta_supply_level = device_status.get('devicestatuspage-suppliesstatus-magentasupply-percentremaining', 0)
  1083.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1084.                          'type' : AGENT_TYPE_MAGENTA,
  1085.                          'health' : 0,
  1086.                          'level' : magenta_supply_level,
  1087.                          'level-trigger' : 0,
  1088.                       })
  1089.  
  1090.         yellow_supply_level = device_status.get('devicestatuspage-suppliesstatus-yellowsupply-percentremaining', 0)
  1091.         agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1092.                          'type' : AGENT_TYPE_YELLOW,
  1093.                          'health' : 0,
  1094.                          'level' : yellow_supply_level,
  1095.                          'level-trigger' : 0,
  1096.                       })
  1097.  
  1098.     return {'revision' :    STATUS_REV_UNKNOWN,
  1099.              'agents' :      agents,
  1100.              'top-door' :    0,
  1101.              'supply-door' : 0,
  1102.              'duplexer' :    1,
  1103.              'photo-tray' :  0,
  1104.              'in-tray1' :    1,
  1105.              'in-tray2' :    1,
  1106.              'media-path' :  1,
  1107.              'status-code' : TYPE6_STATUS_CODE_MAP.get(status_code, STATUS_PRINTER_IDLE),
  1108.            }     
  1109.  
  1110. # PJL status codes
  1111. PJL_STATUS_MAP = {
  1112.     10001: STATUS_PRINTER_IDLE, # online
  1113.     10002: STATUS_PRINTER_OFFLINE, # offline
  1114.     10003: STATUS_PRINTER_WARMING_UP,
  1115.     10004: STATUS_PRINTER_BUSY, # self test
  1116.     10005: STATUS_PRINTER_BUSY, # reset
  1117.     10006: STATUS_PRINTER_LOW_TONER,
  1118.     10007: STATUS_PRINTER_CANCELING,
  1119.     10010: STATUS_PRINTER_SERVICE_REQUEST,
  1120.     10011: STATUS_PRINTER_OFFLINE,
  1121.     10013: STATUS_PRINTER_BUSY,
  1122.     10014: STATUS_PRINTER_REPORT_PRINTING,
  1123.     10015: STATUS_PRINTER_BUSY,
  1124.     10016: STATUS_PRINTER_BUSY,
  1125.     10017: STATUS_PRINTER_REPORT_PRINTING,
  1126.     10018: STATUS_PRINTER_BUSY,
  1127.     10019: STATUS_PRINTER_BUSY,
  1128.     10020: STATUS_PRINTER_BUSY,
  1129.     10021: STATUS_PRINTER_BUSY,
  1130.     10022: STATUS_PRINTER_REPORT_PRINTING,
  1131.     10023: STATUS_PRINTER_PRINTING,
  1132.     10024: STATUS_PRINTER_SERVICE_REQUEST,
  1133.     10025: STATUS_PRINTER_SERVICE_REQUEST,
  1134.     10026: STATUS_PRINTER_BUSY,
  1135.     10027: STATUS_PRINTER_MEDIA_JAM,
  1136.     10028: STATUS_PRINTER_REPORT_PRINTING,
  1137.     10029: STATUS_PRINTER_PRINTING,
  1138.     10030: STATUS_PRINTER_BUSY,
  1139.     10031: STATUS_PRINTER_BUSY,
  1140.     10032: STATUS_PRINTER_BUSY,
  1141.     10033: STATUS_PRINTER_SERVICE_REQUEST,
  1142.     10034: STATUS_PRINTER_CANCELING,
  1143.     10035: STATUS_PRINTER_PRINTING,
  1144.     10036: STATUS_PRINTER_WARMING_UP,
  1145.     10200: STATUS_PRINTER_LOW_BLACK_TONER,
  1146.     10201: STATUS_PRINTER_LOW_CYAN_TONER,
  1147.     10202: STATUS_PRINTER_LOW_MAGENTA_TONER,
  1148.     10203: STATUS_PRINTER_LOW_YELLOW_TONER,
  1149.     10204: STATUS_PRINTER_LOW_TONER, # order image drum
  1150.     10205: STATUS_PRINTER_LOW_BLACK_TONER, # order black drum
  1151.     10206: STATUS_PRINTER_LOW_CYAN_TONER, # order cyan drum
  1152.     10207: STATUS_PRINTER_LOW_MAGENTA_TONER, # order magenta drum
  1153.     10208: STATUS_PRINTER_LOW_YELLOW_TONER, # order yellow drum
  1154.     10209: STATUS_PRINTER_LOW_BLACK_TONER,
  1155.     10210: STATUS_PRINTER_LOW_CYAN_TONER,
  1156.     10211: STATUS_PRINTER_LOW_MAGENTA_TONER,
  1157.     10212: STATUS_PRINTER_LOW_YELLOW_TONER,
  1158.     10213: STATUS_PRINTER_SERVICE_REQUEST, # order transport kit
  1159.     10214: STATUS_PRINTER_SERVICE_REQUEST, # order cleaning kit
  1160.     10215: STATUS_PRINTER_SERVICE_REQUEST, # order transfer kit
  1161.     10216: STATUS_PRINTER_SERVICE_REQUEST, # order fuser kit
  1162.     10217: STATUS_PRINTER_SERVICE_REQUEST, # maintenance
  1163.     10218: STATUS_PRINTER_LOW_TONER,
  1164.     10300: STATUS_PRINTER_LOW_BLACK_TONER, # replace black toner
  1165.     10301: STATUS_PRINTER_LOW_CYAN_TONER, # replace cyan toner
  1166.     10302: STATUS_PRINTER_LOW_MAGENTA_TONER, # replace magenta toner
  1167.     10303: STATUS_PRINTER_LOW_YELLOW_TONER, # replace yellow toner
  1168.     10304: STATUS_PRINTER_SERVICE_REQUEST, # replace image drum
  1169.     10305: STATUS_PRINTER_SERVICE_REQUEST, # replace black drum
  1170.     10306: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan drum
  1171.     10307: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta drum
  1172.     10308: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow drum
  1173.     10309: STATUS_PRINTER_SERVICE_REQUEST, # replace black cart
  1174.     10310: STATUS_PRINTER_SERVICE_REQUEST, # replace cyan cart
  1175.     10311: STATUS_PRINTER_SERVICE_REQUEST, # replace magenta cart
  1176.     10312: STATUS_PRINTER_SERVICE_REQUEST, # replace yellow cart
  1177.     10313: STATUS_PRINTER_SERVICE_REQUEST, # replace transport kit
  1178.     10314: STATUS_PRINTER_SERVICE_REQUEST, # replace cleaning kit
  1179.     10315: STATUS_PRINTER_SERVICE_REQUEST, # replace transfer kit
  1180.     10316: STATUS_PRINTER_SERVICE_REQUEST, # replace fuser kit
  1181.     10317: STATUS_PRINTER_SERVICE_REQUEST,
  1182.     10318: STATUS_PRINTER_SERVICE_REQUEST, # replace supplies
  1183.     10400: STATUS_PRINTER_NON_HP_INK, # [sic]
  1184.     10401: STATUS_PRINTER_IDLE,
  1185.     10402: STATUS_PRINTER_SERVICE_REQUEST,
  1186.     10403: STATUS_PRINTER_IDLE,
  1187.     # 11xyy - Background paper-loading
  1188.     # 12xyy - Background paper-tray status
  1189.     # 15xxy - Output-bin status
  1190.     # 20xxx - PJL parser errors
  1191.     # 25xxx - PJL parser warnings
  1192.     # 27xxx - PJL semantic errors
  1193.     # 30xxx - Auto continuable conditions
  1194.     30119: STATUS_PRINTER_MEDIA_JAM,
  1195.     # 32xxx - PJL file system errors
  1196.     # 35xxx - Potential operator intervention conditions
  1197.     # 40xxx - Operator intervention conditions
  1198.     40021: STATUS_PRINTER_DOOR_OPEN,
  1199.     40022: STATUS_PRINTER_MEDIA_JAM,
  1200.     40038: STATUS_PRINTER_LOW_TONER,
  1201.     40600: STATUS_PRINTER_NO_TONER,
  1202.     # 41xyy - Foreground paper-loading messages
  1203.     # 43xyy - Optional paper handling device messages
  1204.     # 44xyy - LJ 4xxx/5xxx paper jam messages
  1205.     # 50xxx - Hardware errors
  1206.     # 55xxx - Personality errors
  1207.  
  1208. }
  1209.  
  1210. MIN_PJL_ERROR_CODE = 10001
  1211. DEFAULT_PJL_ERROR_CODE = 10001
  1212.  
  1213. def MapPJLErrorCode(error_code, str_code=None):
  1214.     if error_code < MIN_PJL_ERROR_CODE:
  1215.         return STATUS_PRINTER_BUSY
  1216.  
  1217.     if str_code is None:
  1218.         str_code = str(error_code)
  1219.         
  1220.     if len(str_code) < 5:
  1221.         return STATUS_PRINTER_BUSY
  1222.  
  1223.     status_code = PJL_STATUS_MAP.get(error_code, None)
  1224.  
  1225.     if status_code is None:
  1226.         status_code = STATUS_PRINTER_BUSY
  1227.  
  1228.         if 10999 < error_code < 12000: # 11xyy - Background paper-loading
  1229.             # x = tray #
  1230.             # yy = media code
  1231.             tray = int(str_code[2])
  1232.             media = int(str_code[3:])
  1233.             log.debug("Background paper loading for tray #%d" % tray)
  1234.             log.debug("Media code = %d" % media)
  1235.  
  1236.         elif 11999 < error_code < 13000: # 12xyy - Background paper-tray status
  1237.             # x = tray #
  1238.             # yy = status code
  1239.             tray = int(str_code[2])
  1240.             status = int(str_code[3:])
  1241.             log.debug("Background paper tray status for tray #%d" % tray)
  1242.             log.debug("Status code = %d" % status)
  1243.  
  1244.         elif 14999 < error_code < 16000: # 15xxy - Output-bin status
  1245.             # xx = output bin
  1246.             # y = status code
  1247.             bin = int(str_code[2:4])
  1248.             status = int(str_code[4])
  1249.             log.debug("Output bin full for bin #%d" % bin)
  1250.             status_code = STATUS_PRINTER_OUTPUT_BIN_FULL
  1251.  
  1252.         elif 19999 < error_code < 28000: # 20xxx, 25xxx, 27xxx PJL errors
  1253.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1254.  
  1255.         elif 29999 < error_code < 31000: # 30xxx - Auto continuable conditions
  1256.             log.debug("Auto continuation condition #%d" % error_code)
  1257.             status_code = STATUS_PRINTER_BUSY
  1258.  
  1259.         elif 34999 < error_code < 36000: # 35xxx - Potential operator intervention conditions
  1260.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1261.  
  1262.         elif 39999 < error_code < 41000: # 40xxx - Operator intervention conditions
  1263.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1264.  
  1265.         elif 40999 < error_code < 42000: # 41xyy - Foreground paper-loading messages
  1266.             # x = tray
  1267.             # yy = media code
  1268.             tray = int(str_code[2])
  1269.             media = int(str_code[3:])
  1270.             log.debug("Foreground paper loading for tray #%d" % tray)
  1271.             log.debug("Media code = %d" % media)
  1272.             status_code = STATUS_PRINTER_OUT_OF_PAPER
  1273.  
  1274.         elif 41999 < error_code < 43000:
  1275.             status_code = STATUS_PRINTER_MEDIA_JAM
  1276.  
  1277.         elif 42999 < error_code < 44000: # 43xyy - Optional paper handling device messages
  1278.             status_code = STATUS_PRINTER_SERVICE_REQUEST
  1279.  
  1280.         elif 43999 < error_code < 45000: # 44xyy - LJ 4xxx/5xxx paper jam messages
  1281.             status_code = STATUS_PRINTER_MEDIA_JAM
  1282.  
  1283.         elif 49999 < error_code < 51000: # 50xxx - Hardware errors
  1284.             status_code = STATUS_PRINTER_HARD_ERROR
  1285.  
  1286.         elif 54999 < error_code < 56000 : # 55xxx - Personality errors
  1287.             status_code = STATUS_PRINTER_HARD_ERROR
  1288.  
  1289.     log.debug("Mapped PJL error code %d to status code %d" % (error_code, status_code))
  1290.     return status_code
  1291.  
  1292.  
  1293. pjl_code_pat = re.compile("""^CODE\s*=\s*(\d.*)$""", re.IGNORECASE)
  1294.  
  1295.  
  1296.  
  1297. def StatusType8(dev): #  LaserJet PJL (B&W only)
  1298.     try:
  1299.         # Will error if printer is busy printing...
  1300.         dev.openPrint()
  1301.     except Error, e:
  1302.         log.warn(e.msg)
  1303.         status_code = STATUS_PRINTER_BUSY
  1304.     else:
  1305.         try:
  1306.             dev.writePrint("\x1b%-12345X@PJL INFO STATUS \r\n\x1b%-12345X")
  1307.             pjl_return = dev.readPrint(1024, timeout=5, allow_short_read=True)
  1308.             dev.close()
  1309.  
  1310.             log.debug_block("PJL return:", pjl_return)
  1311.  
  1312.             str_code = '10001'
  1313.  
  1314.             for line in pjl_return.splitlines():
  1315.                 line = line.strip()
  1316.                 match = pjl_code_pat.match(line)
  1317.  
  1318.                 if match is not None:
  1319.                     str_code = match.group(1)
  1320.                     break
  1321.  
  1322.             log.debug("Code = %s" % str_code)
  1323.  
  1324.             try:
  1325.                 error_code = int(str_code)
  1326.             except ValueError:
  1327.                 error_code = DEFAULT_PJL_ERROR_CODE
  1328.  
  1329.             log.debug("Error code = %d" % error_code)
  1330.  
  1331.             status_code = MapPJLErrorCode(error_code, str_code)
  1332.         
  1333.         finally:
  1334.             try:
  1335.                 dev.closePrint()
  1336.             except Error:
  1337.                 pass
  1338.     
  1339.     agents = []
  1340.  
  1341.     # TODO: Only handles mono lasers...
  1342.     if status_code in (STATUS_PRINTER_LOW_TONER, STATUS_PRINTER_LOW_BLACK_TONER):
  1343.         health = AGENT_HEALTH_OK
  1344.         level_trigger = AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT
  1345.         level = 0
  1346.  
  1347.     elif status_code == STATUS_PRINTER_NO_TONER:
  1348.         health = AGENT_HEALTH_MISINSTALLED
  1349.         level_trigger = AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT
  1350.         level = 0
  1351.  
  1352.     else:
  1353.         health = AGENT_HEALTH_OK
  1354.         level_trigger = AGENT_LEVEL_TRIGGER_SUFFICIENT_0
  1355.         level = 100
  1356.  
  1357.     log.debug("Agent: health=%d, level=%d, trigger=%d" % (health, level, level_trigger))
  1358.  
  1359.  
  1360.     agents.append({  'kind' : AGENT_KIND_TONER_CARTRIDGE,
  1361.                      'type' : AGENT_TYPE_BLACK,
  1362.                      'health' : health,
  1363.                      'level' : level,
  1364.                      'level-trigger' : level_trigger,
  1365.                   })
  1366.  
  1367.     if status_code == 40021:
  1368.         top_door = 0
  1369.     else:
  1370.         top_door = 1
  1371.  
  1372.     log.debug("Status code = %d" % status_code)
  1373.  
  1374.     return { 'revision' :    STATUS_REV_UNKNOWN,
  1375.              'agents' :      agents,
  1376.              'top-door' :    top_door,
  1377.              'supply-door' : top_door,
  1378.              'duplexer' :    0,
  1379.              'photo-tray' :  0,
  1380.              'in-tray1' :    1,
  1381.              'in-tray2' :    1,
  1382.              'media-path' :  1,
  1383.              'status-code' : status_code,
  1384.            }     
  1385.  
  1386.  
  1387.  
  1388.  
  1389.